Profesor, MAF ITESO
En primer lugar, para poder bajar precios de Yahoo, es necesario cargar algunos paquetes de Python. En este caso, el paquete principal será Pandas. También, se usarán el Scipy y el Numpy para las matemáticas necesarias y, el Matplotlib para hacer gráficos de las series de datos.
In [1]:
#importar los paquetes que se van a usar
import pandas as pd
import pandas_datareader.data as web
import numpy as np
import datetime
import matplotlib.pyplot as plt
import scipy.stats as stats
%matplotlib inline
#algunas opciones para Python
pd.set_option('display.notebook_repr_html', False)
pd.set_option('display.max_columns', 6)
pd.set_option('display.max_rows', 10)
pd.set_option('display.width', 78)
pd.set_option('precision', 3)
Una vez cargados los paquetes, es necesario definir los tickers de las acciones que se usarán, la fuente de descarga (Yahoo en este caso, pero también se puede desde Google) y las fechas de interés. Con esto, la función DataReader del paquete pandas_datareader bajará los precios solicitados.
Nota: Usualmente, las distribuciones de Python no cuentan, por defecto, con el paquete pandas_datareader. Por lo que será necesario instalarlo aparte. El siguiente comando instala el paquete en Anaconda: conda install -c conda-forge pandas-datareader
In [2]:
#Descargar datos de Yahoo! finance
#Tickers
tickers = ['AA','AAPL','MSFT', '^GSPC']
# Fuente
data_source = 'yahoo'
# Fechas: desde 01/01/2014 hasta 12/31/2016.
start_date = '2014-01-01'
end_date = '2016-12-31'
# Usar el pandas data reader. El comando sort_index ordena los datos por fechas
assets = (web.DataReader(tickers, data_source, start_date, end_date)).sort_index('major_axis')
Nota: Para descargar datos de la bolsa mexicana de valores (BMV), el ticker debe tener la extensión MX. Por ejemplo: MEXCHEM.MX, LABB.MX, GFINBURO.MX y GFNORTEO.MX.
Como se puede notar, en este caso se consideran tres activos (Alcoa, Apple y Microsoft) y, el índice S&P500. Todos almacenados en la variable assets, que tiene la siguiente estructura:
In [3]:
assets
Out[3]:
El objeto assets tiene tres características: items, major_axis y minor_axis. Con estos, se pueden encontrar todos los registros almacenados.
In [4]:
assets.items
Out[4]:
In [5]:
assets.minor_axis
Out[5]:
In [6]:
assets.major_axis
Out[6]:
De esta forma, es ordenar y acceder a los datos de una forma simple e intuitiva. Por ejemplo: los precios de cierre de Microsoft.
In [7]:
assets['Adj Close']['MSFT']
Out[7]:
O, los precios de apertura de Apple
In [8]:
assets['Open']['AAPL']
Out[8]:
También, los precios de cierre en la fecha 2014-01-14
In [9]:
assets.major_xs('2014-01-14')['Close']
Out[9]:
O, finalmente, los valores del S&P500
In [10]:
assets.minor_xs('^GSPC')
Out[10]:
De donde, se pueden seleccionar los precios de cierre y ajustados en el cierre
In [11]:
assets.minor_xs('^GSPC')[['Close', 'Adj Close']]
Out[11]:
En primer lugar, se toma como ejemplo la serie de precios de cierre de Microsoft, así como el volumen de transacciones.
In [12]:
msftA=assets['Adj Close']['MSFT']
msftV=assets['Volume']['MSFT']
msftA
Out[12]:
El gráfico de esta serie se obtiene de forma simple mediante el siguiente comando:
In [13]:
msftA.plot(figsize=(12,8));
De forma similar, se grafica la serie de volúmenes de transacción
In [14]:
msftV.plot(figsize=(12,8));
Un procedimiento análogo puede aplicarse sobre todas las series de datos en forma simultánea. En primer lugar, se obtienen todos los precios de cierre:
In [15]:
allA=assets['Adj Close']
allA
Out[15]:
Y una vez obtenidos, se grafican.
In [16]:
assets['Adj Close'].plot(figsize=(12,8));
En el gráfico anterior, es difícil observar el comportamiento de las acciones debido a su diferencia de magnitud con respecto al S&P500. Por esto, se seleccionan unicamente las series de tiempo de los precios de las acciones.
In [17]:
allassetsA=assets['Adj Close'][['AA', 'AAPL', 'MSFT']]
Luego, se dibujan de forma conjunta.
In [18]:
allassetsA.plot(figsize=(12,8));
Usualmente, es conveniente graficar al precio de cierre de una acción en conjunto con si volumen de transacciones. El siguiente es un ejemplo de esta clase de graficas para el caso de Microsoft.
In [19]:
top = plt.subplot2grid((4,4), (0, 0), rowspan=3, colspan=4)
top.plot(msftA.index, msftA, label='Precio ajustado en el cierre')
plt.title('Microsoft: Precio ajustado en el cierre 2014 - 2016')
plt.legend(loc=2)
bottom = plt.subplot2grid((4,4), (3,0), rowspan=1, colspan=4)
bottom.bar(msftV.index, msftV)
plt.title('Microsoft: Volumen diario de transacción de la acción')
plt.gcf().set_size_inches(12,8)
plt.subplots_adjust(hspace=0.75)
Otro procedimiento que se efectúa con freciencia es el cálculo de promedios y desviaciones móviles para la serie de precios. Los promedios móviles se calculan mediante:
In [20]:
short_rollmean_msft = msftA.rolling(window=20).mean()
long_rollmean_msft = msftA.rolling(window=100).mean()
In [21]:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(msftA.index, msftA, label='Precio ajustado Microsoft')
ax.plot(short_rollmean_msft.index, short_rollmean_msft, label='Media móvil con ventana de 20 días')
ax.plot(long_rollmean_msft.index, long_rollmean_msft, label='Media móvil con ventana de 100 días')
plt.gcf().set_size_inches(12,8)
ax.set_xlabel('Date')
ax.set_ylabel('Microsoft: Precio ajustado en el cierre 2014 - 2016')
ax.legend()
Out[21]:
Y las desvaciones móviles, con la instrucción:
In [22]:
short_rollstd_msft = msftA.rolling(window=20).std()
long_rollstd_msft = msftA.rolling(window=100).std()
In [23]:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(msftA.index, msftA, label='Precio ajustado Microsoft')
ax.plot(short_rollstd_msft.index, msftA+short_rollstd_msft, color="y", label='Precio + Desviación móvil con ventana de 20 días')
ax.plot(short_rollstd_msft.index, msftA-short_rollstd_msft, color="y", label='Precio - Desviación móvil con ventana de 20 días')
plt.gcf().set_size_inches(12,8)
ax.set_xlabel('Date')
ax.set_ylabel('Microsoft: Precio ajustado en el cierre 2014 - 2016')
ax.legend()
Out[23]:
In [24]:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(msftA.index, msftA, label='Precio ajustado Microsoft')
ax.plot(long_rollstd_msft.index, msftA+long_rollstd_msft, color="y", label='Precio + Desviación móvil con ventana de 100 días')
ax.plot(long_rollstd_msft.index, msftA-long_rollstd_msft, color="y", label='Precio - Desviación móvil con ventana de 100 días')
plt.gcf().set_size_inches(12,8)
ax.set_xlabel('Date')
ax.set_ylabel('Microsoft: Precio ajustado en el cierre 2014 - 2016')
ax.legend()
Out[24]:
Para una sucesión de precios $\{S_t\}_{t=0}^{n}$, el rendimiento simple $R_t$ se define como el el cambio porcentual $$ R_t=\frac{S_t-S_{t-1}}{S_{t-1}} $$ para $t=1,\ldots,n$.
Para el ejemplo en curso, la fórmula anterior se puede implementar para todos los precios de cierre de manera simultánea mediante
In [25]:
R = ((allA - allA.shift(1))/allA)[1:]
R
Out[25]:
Otra manera de calcular el rendimiento simple es usando el comando de cambio porcentual.
In [26]:
(allA.pct_change())[1:]
Out[26]:
Una gráfica de los rendimientos se obtiene con el comando
In [27]:
R.plot(figsize=(12,8));
Donde se observa que el rendimiento tiene una tendencia constante y, por tanto, se puede plantear la hipótesis de se puede modelar usando un proceso estocástico estacionario en media.
Otro rendimiento usado con frecuencia es el rendimiento continuamente compuesto o rendimiento logaritmico. Éste, está definido como $$ r_t=\ln(1+R_t) $$ donde $R_t$ es el rendimiento simple. Es fácil darse cuenta que $r_t=\ln\left(\frac{S_t}{S_{t-1}}\right)$.
Para este caso, la fórmula del rendimiento continuamente compuesto se translada facilmente a código Python.
In [28]:
r=np.log(1+R)
r
Out[28]:
Una gráfica de los rendimientos se obtiene con el comando
In [29]:
r.plot(figsize=(12,8))
Out[29]:
In [30]:
R.describe()
Out[30]:
In [31]:
r.describe()
Out[31]:
In [32]:
Rmsft=(msftA.pct_change())[1:]
Rmsft
Out[32]:
In [33]:
short_rollmean_Rmsft = Rmsft.rolling(window=20).mean()
long_rollmean_Rmsft = Rmsft.rolling(window=100).mean()
short_rollstd_Rmsft = Rmsft.rolling(window=20).std()
long_rollstd_Rmsft = Rmsft.rolling(window=100).std()
In [34]:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(Rmsft.index, Rmsft, label='Rendimiento Microsoft')
ax.plot(short_rollmean_Rmsft.index, short_rollmean_Rmsft, label='Media móvil con ventana de 20 días')
ax.plot(long_rollmean_Rmsft.index, long_rollmean_Rmsft, label='Media móvil con ventana de 100 días')
plt.gcf().set_size_inches(12,8)
ax.set_xlabel('Date')
ax.set_ylabel('Microsoft: Rendimientos 2014 - 2016')
ax.legend()
Out[34]:
In [35]:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(Rmsft.index, Rmsft, label='Rendimiento Microsoft')
ax.plot(short_rollstd_Rmsft.index, short_rollstd_Rmsft, color="y", label='Desviación móvil con ventana de 20 días')
ax.plot(short_rollstd_Rmsft.index, -short_rollstd_Rmsft, color="y", label='- Desviación móvil con ventana de 20 días')
plt.gcf().set_size_inches(12,8)
ax.set_xlabel('Date')
ax.set_ylabel('Microsoft: Rendimiento cierre 2014 - 2016')
ax.legend()
Out[35]:
In [36]:
min_periods = 20
vol = R.rolling(window=min_periods).std()*np.sqrt(min_periods)
vol.plot(figsize=(10, 8))
Out[36]:
In [37]:
min_periods = 20
vol = r.rolling(window=min_periods).std()*np.sqrt(min_periods)
vol.plot(figsize=(10, 8))
Out[37]:
In [38]:
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.plot(Rmsft.index, Rmsft, label='Rendimiento Microsoft')
ax.plot(long_rollstd_Rmsft.index, long_rollstd_Rmsft, color="y", label='Desviación móvil con ventana de 20 días')
ax.plot(long_rollstd_Rmsft.index, -long_rollstd_Rmsft, color="y", label='- Desviación móvil con ventana de 20 días')
plt.gcf().set_size_inches(12,8)
ax.set_xlabel('Date')
ax.set_ylabel('Microsoft: Rendimiento cierre 2014 - 2016')
ax.legend()
Out[38]:
In [39]:
Rcum = (1 + R).cumprod()
Rcum
Out[39]:
In [40]:
Rcum.plot(figsize=(12,8));
In [41]:
rcum=np.exp(r.cumsum())
rcum
Out[41]:
In [42]:
rcum.plot(figsize=(12,8));
In [43]:
R.hist(bins=50, sharex=True, figsize=(12,8));
In [44]:
r.hist(bins=50, sharex=True, figsize=(12,8));
In [45]:
f = plt.figure(figsize=(12,8))
ax = f.add_subplot(111)
stats.probplot(Rmsft, dist='norm', plot=ax)
plt.show();
In [46]:
Rmsft.plot(kind='box', figsize=(3,6));
In [47]:
R.plot(kind='box', figsize=(12,8));
In [48]:
pd.plotting.scatter_matrix(R, diagonal='kde', alpha=0.1, figsize=(8,8));
In [ ]: